package com.uci.photogam;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.EmbossMaskFilter;
import android.graphics.MaskFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class ViewImageEdit extends SurfaceView implements Runnable {
	public Bitmap bitmap;
	private Canvas canvas;
	private MaskFilter emboss, blur;
	private Paint paint;
	private Path path;
	private Thread t;
	private SurfaceHolder holder;
	private boolean utilized = true;
	private int strokeWidth = 6;
	// PANNING
	private volatile boolean running = false;
	private float xImg, yImg, xScrollAmount, yScrollAmount, xDown, yDown,
			xPrev, yPrev, xEditPrev, yEditPrev;
	public volatile boolean toggleEditImag = true;

	// SCALE
	private static float MIN_ZOOM = 1f;
	private static float MAX_ZOOM = 5f;
	private float scaleFactor = 1.f;
	private ScaleGestureDetector sDectector;

	public ViewImageEdit(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
	}

	private void init() {
		emboss = new EmbossMaskFilter(new float[] { 1, 1, 1 }, 0.4f, 6, 3.5f);
		blur = new BlurMaskFilter(5, BlurMaskFilter.Blur.NORMAL);

		path = new Path();
		paint = new Paint();
		paint.setColor(Color.BLACK);
		paint.setDither(true);
		paint.setStyle(Paint.Style.STROKE);
		paint.setStrokeJoin(Paint.Join.ROUND);
		paint.setStrokeCap(Paint.Cap.ROUND);
		paint.setAntiAlias(true);
		paint.setXfermode(null);
		paint.setStrokeWidth(strokeWidth);
		paint.setMaskFilter(null);
		holder = this.getHolder();
		xImg = yImg = xDown = yDown = xPrev = yPrev = 0;

		sDectector = new ScaleGestureDetector(getContext(), new ScaleListener());
	}

	public void setBitmap(String imgPath) {
		if (imgPath.startsWith("http")) {
			try {
				bitmap = BitmapFactory.decodeStream((InputStream) new URL(
						imgPath).getContent());
			} catch (MalformedURLException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
			bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
			bitmap = Bitmap.createScaledBitmap(bitmap, 1024, 800, false);

		} else {
			bitmap = BitmapFactory.decodeFile(imgPath);

			int scaleSizeWidth = bitmap.getWidth() / 1024;
			int scaleSizeHeight = bitmap.getHeight() / 800;

			bitmap = Bitmap.createScaledBitmap(bitmap, bitmap.getWidth()
					/ scaleSizeWidth, bitmap.getHeight() / scaleSizeHeight,
					false);
		}
		canvas = new Canvas(bitmap);
	}

	public void run() {
		while (running) {
			if (holder.getSurface().isValid() && true) {
				Canvas canvas = holder.lockCanvas();
				canvas.scale(scaleFactor, scaleFactor);
				canvas.drawColor(paint.getColor());
				if (this.toggleEditImag) {
					canvas.drawBitmap(bitmap, xImg, yImg, paint);
					canvas.drawPath(path, paint);
				} else {
					float xNewImg = xScrollAmount;
					float yNewImg = yScrollAmount;
					if (yNewImg > 0) {
						yNewImg = -0.5f;
						yScrollAmount = -0.5f;
					}
					if (xNewImg > 0) {
						xNewImg = -0.5f;
						xScrollAmount = -0.5f;
					}
					if (-(bitmap.getHeight() - canvas.getHeight()) > yNewImg) {
						yNewImg = (float) -(bitmap.getHeight()
								- canvas.getHeight() + 2);
						yScrollAmount = (float) -(bitmap.getHeight()
								- canvas.getHeight() + 2);
					}
					if (-(bitmap.getWidth() - canvas.getWidth()) > xNewImg) {
						xNewImg = (float) -(bitmap.getWidth()
								- canvas.getWidth() + 2);
						xScrollAmount = (float) -(bitmap.getWidth()
								- canvas.getWidth() + 2);
					}

					canvas.drawBitmap(bitmap, xNewImg, yNewImg, paint);
					xImg = xNewImg;
					yImg = yNewImg;
				}
				holder.unlockCanvasAndPost(canvas);
			}
			try {
				Thread.sleep(50);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	public boolean onTouchEvent(MotionEvent event) {
		float x = event.getX();
		float y = event.getY();
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			utilized = true;
			if (toggleEditImag) {
				path.reset();
				pathDown(x, y);
			} else {
				xDown = x - xPrev;
				yDown = y - yPrev;
			}
			break;
		case MotionEvent.ACTION_MOVE:
			if (toggleEditImag) {
				pathMove(x, y);
			} else {
				xScrollAmount = x - xDown;
				yScrollAmount = y - yDown;
			}
			break;
		case MotionEvent.ACTION_UP:
			utilized = false;
			if (toggleEditImag) {
				pathUp(x, y);
				path.reset();
			} else {
				yDown = xDown = 0;
				xPrev = xScrollAmount;
				yPrev = yScrollAmount;
			}
			break;
		}
		invalidate();
		return true;
	}

	private void pathUp(float x, float y) {
		path.lineTo(x, y);
		path.offset(-xImg, -yImg);
		canvas.drawPath(path, paint);
		path.reset();
	}

	private static final int TOUCH_TOLERANCE = 5;

	private void pathMove(float x, float y) {
		float dx = Math.abs(x - xEditPrev);
		float dy = Math.abs(y - yEditPrev);
		if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
			path.quadTo(xEditPrev, yEditPrev, (x + xEditPrev) / 2,
					(y + yEditPrev) / 2);
			setEditPrev(x, y);
		}
	}

	private void pathDown(float x, float y) {
		path.reset();
		path.moveTo(x, y);
		setEditPrev(x, y);
	}

	private void setEditPrev(float x, float y) {
		xEditPrev = x;
		yEditPrev = y;
	}

	public void resumeView() {
		running = true;
		t = new Thread(this);
		t.start();
	}

	public void pauseView() {
		running = false;
		while (true) {
			try {
				t.join();
			} catch (InterruptedException e) {
			}
			break;
		}
		t = null;
	}

	/*** CODE USE BY ACTIVITIES THAT USE THIS VIEW ***/
	public boolean saveImage(FileOutputStream fos) {
		return bitmap.compress(CompressFormat.PNG, 100, fos);
	}

	public void setColor(int color) {
		V.Log("EDIT", color + " type");
		paint.setColor(color);
	}

	public void setStrokeWidth(int n) {
		this.strokeWidth = n;
		paint.setStrokeWidth(n);
	}

	public void setPenType(String type) {
		V.Log("SET", type);
		paint.setStrokeWidth(strokeWidth);
		paint.setXfermode(null);
		if (type.equals(V.PEN_NORMAL))
			paint.setMaskFilter(null);
		else if (type.equals(V.PEN_BLUR))
			paint.setMaskFilter(blur);
		else if (type.equals(V.PEN_EMBOSS))
			paint.setMaskFilter(emboss);
		
		invalidate();
	}

	public void toggleLock() {
		toggleEditImag = (toggleEditImag) ? false : true;
	}

	private class ScaleListener extends
			ScaleGestureDetector.SimpleOnScaleGestureListener {
		public boolean onScale(ScaleGestureDetector detector) {
			scaleFactor *= detector.getScaleFactor();
			scaleFactor = Math.max(MIN_ZOOM, Math.min(scaleFactor, MAX_ZOOM));
			return true;
		}
	}
	
	public void scaleImage(int newWidth) {
		
		if(bitmap.getWidth() != newWidth)
		{
			float scale = (float)newWidth / bitmap.getWidth();
			bitmap = Bitmap.createScaledBitmap(bitmap, newWidth, (int)(scale*bitmap.getHeight()), true);
		}
		
		
	}

}
